/*:
* @plugindesc (v1.01)敌人职业
* @author 小c
* @version 1.0.1
* @date 10/14/2020
*
* @help
* 敌人职业/种族系统，使职业特性与敌人挂钩。
* 建议将插件放在YEP_BattleEngineCore和YEP_AutoPassiveStates下面。
*
* 敌人职业
* 敌人标签
* <Enemy Class: x>
* 指定敌人职业，x为职业id。
* 
* 敌人转职
* 插件指令
* EnemyChangeClass [index] [classId]
* 位置在index的敌人转职为classId对应的职业
* index最小值为1。
* 例：EnemyChangeClass 1 5
* 给第1个敌人【$gameTroop.members()[0]】转职为职业5
*
* 敌人职业属性公式
* 职业标签
* <Enemy Class Param>
* mhp = 1.5 * base.mhp + 25;
* agi = 0.9 * base.agi;
* </Enemy Class Param>
* 如上例，职业对敌人基础属性的修正公式。
* base对象保存敌人的原始基础属性。
* 职业中的参数曲线对敌人无效。
*
* 此插件只对职业中的【特性】起效。
* 职业中配置的大部分标签都不会对敌人起效，若需要进行其他的操作，可在
* 职业中配置被动状态，此处需要YEP_AutoPassiveStates支持。
*
* 若使用了YEP_BattleEngineCore，敌人将无条件学会职业中指定的所有技能。
*
* JavaScript函数
* enemy.isClass(classId) 敌人是否为指定职业
* enemy.changeClass(classId) 敌人转职
*
* 更新日志
* v1.00
* 插件完成
*
* v1.01
* 添加敌人转职功能
*/

var Imported = Imported || {};
Imported.CP_EnemyClass = true;

var CP = CP || {};
CP.EnemyClassManager = CP.EnemyClassManager || {};

CP.EnemyClassManager.DATABASE_LOADED = DataManager.isDatabaseLoaded;
DataManager.isDatabaseLoaded = function(){
	if(!CP.EnemyClassManager.DATABASE_LOADED.call(this))
		return false;

	CP.EnemyClassManager.loadEnemyClass();
	CP.EnemyClassManager.loadEnemyClassParam();

	return true;
};

CP.EnemyClassManager.loadEnemyClass = function(){
	for(var i = 1; i < $dataEnemies.length; i++){
		var enemy = $dataEnemies[i];
		enemy.classId = 0;

		if(enemy.meta["Enemy Class"])
			enemy.classId = Number(enemy.meta["Enemy Class"]) || 0;
	}
};

CP.EnemyClassManager.loadEnemyClassParam = function(){
	var reg = /<Enemy Class Param>([\S\s]*)<\/Enemy Class Param>/;
	for(var i = 1; i < $dataClasses.length; i++){
		var cls = $dataClasses[i];
		cls.enemyParam = null;
		if(reg.exec(cls.note))
			cls.enemyParam = RegExp.$1;
	}
};

//-----------------------------
//  Game_Enemy
//-----------------------------
CP.EnemyClassManager.SETUP_ENEMY = Game_Enemy.prototype.setup;
Game_Enemy.prototype.setup = function(enemyId, x, y) {
	var enemy = $dataEnemies[enemyId];

	this._classId = 0;
	if(enemy)
		this._classId = enemy.classId;

	CP.EnemyClassManager.SETUP_ENEMY.call(this, enemyId, x, y);
};

Game_Enemy.prototype.currentClass = function() {
    return $dataClasses[this._classId];
};

Game_Enemy.prototype.isClass = function(classId){
	return this._classId > 0 && this._classId === classId;
};

CP.EnemyClassManager.ENEMY_TRAIT_OBJECTS = Game_Enemy.prototype.traitObjects;
Game_Enemy.prototype.traitObjects = function(){
    var objects = CP.EnemyClassManager.ENEMY_TRAIT_OBJECTS.call(this);
    var cls = this.currentClass();
    if(cls)
    	return objects.concat(cls);
    else
    	return objects;
};

CP.EnemyClassManager.ENEMY_PARAM_BASE = Game_Enemy.prototype.paramBase;
Game_Enemy.prototype.paramBase = function(paramId){
	var base = this.databaseParamObject();
	var mhp = base.mhp;
	var mmp = base.mmp;
	var atk = base.atk;
	var def = base.def;
	var mat = base.mat;
	var mdf = base.mdf;
	var agi = base.agi;
	var luk = base.luk;
	var cls = this.currentClass();

	if(cls && cls.enemyParam){
		try{
			eval(cls.enemyParam);
		}catch(err){
			console.error(err);
		}
	}
    
    switch(paramId){
    	case 0:
    		return mhp;
    	case 1:
    		return mmp;
    	case 2:
    		return atk;
    	case 3:
    		return def;
    	case 4:
    		return mat;
    	case 5:
    		return mdf;
    	case 6:
    		return agi;
    	case 7:
    		return luk;
    	default:
    		return 0;
    }
};

Game_Enemy.prototype.databaseParamObject = function(){
	var base = {};
	base.mhp = CP.EnemyClassManager.ENEMY_PARAM_BASE.call(this, 0);
	base.mmp = CP.EnemyClassManager.ENEMY_PARAM_BASE.call(this, 1);
	base.atk = CP.EnemyClassManager.ENEMY_PARAM_BASE.call(this, 2);
	base.def = CP.EnemyClassManager.ENEMY_PARAM_BASE.call(this, 3);
	base.mat = CP.EnemyClassManager.ENEMY_PARAM_BASE.call(this, 4);
	base.mdf = CP.EnemyClassManager.ENEMY_PARAM_BASE.call(this, 5);
	base.agi = CP.EnemyClassManager.ENEMY_PARAM_BASE.call(this, 6);
	base.luk = CP.EnemyClassManager.ENEMY_PARAM_BASE.call(this, 7);

	return base;
};

Game_Enemy.prototype.changeClass = function(classId){
	if(!$dataClasses[classId])  return;

	this._classId = classId;
	this.refresh();
};

if(Imported.YEP_BattleEngineCore){

CP.EnemyClassManager.ENEMY_SKILLS = Game_Enemy.prototype.skills;
Game_Enemy.prototype.skills = function(){
	var skills = CP.EnemyClassManager.ENEMY_SKILLS.call(this);
	var cls = this.currentClass();

	if(cls){
		cls.learnings.forEach(function(learn){
			var skill = $dataSkills[learn.skillId];
			if(skill && !skills.contains(skill))
				skills.push(skill);
		});
	}

	return skills;
};

}

if(Imported.YEP_AutoPassiveStates){

CP.EnemyClassManager.ENEMY_PASSIVE_STATE_RAW = Game_Enemy.prototype.passiveStatesRaw;
Game_Enemy.prototype.passiveStatesRaw = function(){
	if(this._passiveStatesRaw !== undefined) return this._passiveStatesRaw;
	var array = CP.EnemyClassManager.ENEMY_PASSIVE_STATE_RAW.call(this);
	array = array.concat(this.getPassiveStateData(this.currentClass()));
    this._passiveStatesRaw = array.filter(Yanfly.Util.onlyUnique)
    return this._passiveStatesRaw;
};

}

//-----------------------------
//  Game_Interpreter
//-----------------------------
CP.EnemyClassManager.PLUGIN_COMMAND = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function(command, args){
	CP.EnemyClassManager.PLUGIN_COMMAND.call(this, command, args);

	if(command == 'EnemyChangeClass'){
		var index = Number(args[0]) || 0;
		var classId = Number(args[1]) || 0;

		var enemy = $gameTroop.members()[index - 1];
		if(!!enemy)
			enemy.changeClass(classId);
	};
};